﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class EnemyManager : MonoBehaviour, IResettable {


    public bool shielded = false;

    public GameObject explosionEffect;

    public List<Vector3> patrolPositions;
    public float patrolSpeed = 2.0f;
    public int targetPatrolPosition = 0;

    private int editorPatrolPoint = 0;

    public float scanStartArc = 30;     // Scanning arc in degrees
    public float currentArc = 30;       // For tracking the current arc
    public float arcFocusRate = 10;     // Rate of arc sharpening in degrees per second, i.e. an arc of 30 degrees will narrow to 0 in 3 seconds
    public float currentArcDirection = 0;   // Current arc direction in degrees
    public float scanSpeed = 90;        // Rate of scan rotation in degrees per second
    public float arcLength = 2;         // Distance from the enemy that can be scanned  

    private Transform player = null;
    private Transform scanningLine = null;
    private ScanLineManager scanLineManager = null;

    private Vector3 startPosition;
    private int startTargetPatrolPosition = 0;

	// Use this for initialization
	void Start () {

        ResetItemList.Instance.AddItem(this);
        ConfigureShielding();

        player = GameObject.FindGameObjectWithTag("Player").transform;

        scanningLine = transform.FindChild("ScanningLine");
        scanLineManager = scanningLine.GetComponent<ScanLineManager>();
        scanLineManager.scanDistance = arcLength;

        startPosition = transform.position;
        startTargetPatrolPosition = targetPatrolPosition;
	}

    void ConfigureShielding()
    {
        if (!shielded)
        {
            this.transform.FindChild("shielding").gameObject.SetActive(false);
        }
    }

	// Update is called once per frame
	void Update () {

        if (!HuntForPlayer())
        {
            Patrol();
        }

    }

    private void Patrol()
    {
        if (patrolPositions.Count >= 1)
        {
            if (transform.position == patrolPositions[targetPatrolPosition])
            {
                targetPatrolPosition++;
                if (targetPatrolPosition >= patrolPositions.Count)
                {
                    targetPatrolPosition = 0;
                }
            }

            Vector3 distanceToTarget = patrolPositions[targetPatrolPosition] - this.transform.position;
            float frameRange = patrolSpeed * Time.deltaTime;
            if (frameRange >= distanceToTarget.magnitude)
            {
                this.transform.position = patrolPositions[targetPatrolPosition];
            }
            else
            {
                this.transform.position += distanceToTarget.normalized * frameRange;
            }

        }
    }

    private bool HuntForPlayer()
    {
        Vector3 huntDirection = scanningLine.right;
        Vector3 playerDirection = player.position - transform.position;
        float angle = Vector3.Angle(huntDirection, playerDirection);

        // Is the angle within the arc?
        if (Mathf.Abs(angle) <= scanningLine.GetComponent<ScanLineManager>().currentArcSize / 2)
        {
            RaycastHit hitInfo;
            if (Physics.Raycast(transform.position, playerDirection, out hitInfo, arcLength))
            {
                if (hitInfo.collider.tag == "Player")
                {
                    scanLineManager.centerRotationRate = angle;
                    // When t = 0, arc is arcSize
                    // When t = 1, arc is arcSize * 0.1f
                    // If we want it to take C seconds, then we need to increment by Time.deltaTime / C
                    // Current time is...
                    // arc = arcSize - 0.9 * t * arcSize
                    // 0.9 * t * arcSize + arc = arcSize
                    // 0.9 * arcSize * t = arcSize - arc
                    // t = (arcSize - arc) / 0.9 * arcSize
                    float currentTime = (scanLineManager.arcSize - scanLineManager.currentArcSize) / (0.9f * scanLineManager.arcSize);
                    currentTime += Time.deltaTime / 3.0f;
                    scanLineManager.currentArcSize = Mathf.Lerp(scanLineManager.arcSize, scanLineManager.arcSize * 0.1f, currentTime);

                    if (currentTime >= 1)
                    {
                        hitInfo.collider.GetComponent<DeathDetection>().Electrocuted();
                    }

                    return true;
                }
            }
        }
        else
        {
            scanLineManager.currentArcSize = scanLineManager.arcSize;
        }

        scanLineManager.centerRotationRate = scanLineManager.normalRotationRate;
        return false;

    }

    void OnCollisionEnter(Collision collision)
    {
        switch (collision.collider.tag)
        {
            case "missile":
                OnStruckByMissile(collision.collider.gameObject);
                break;
            case "energyShot":
                OnStruckByEnergyShot(collision.collider.gameObject);
                break;
            case "teleportShot":
                OnStruckByTeleportShot(collision.collider.gameObject);
                break;
        }

    }

    public void OnPlayerVictory()
    {
        GameObject.Instantiate(explosionEffect, transform.position, Quaternion.identity);
        OnDestroyedByPlayer("levelWon");
    }

    private void OnStruckByTeleportShot(GameObject gameObject)
    {
        TeleportShotManager teleportShotManager = gameObject.GetComponent<TeleportShotManager>();
        teleportShotManager.FinishTeleport();
    }

    private void OnDestroyedByPlayer(string source)
    {
        FollowActionPriorityQueue.Instance.AddFollowPosition(new EnemyDeathPrioritizedFollowPosition(transform.position));
        this.gameObject.SetActive(false);

        GA.API.Design.NewEvent("enemyDestroyed:" + source, transform.position);

    }

    private void OnStruckByEnergyShot(GameObject shot)
    {
        GameObject.Instantiate(explosionEffect, transform.position, Quaternion.identity);
        OnDestroyedByPlayer("energy");
//        shot.GetComponent<EnergyShotManager>().DisconnectTrail();
        shot.GetComponent<EnergyShotManager>().Remove();
    }

    private void OnStruckByMissile(GameObject shot)
    {
        if (!shielded)
        {
            OnDestroyedByPlayer("missile");
        }
        Destroy(shot);
    }

    public void Reset()
    {
        this.gameObject.SetActive(true);
        ConfigureShielding();
        currentArcDirection = 0;
        transform.position = startPosition;
        targetPatrolPosition = startTargetPatrolPosition;
    }

    public bool PersistAfterReset()
    {
        return true;
    }

    public void AddPatrolPosition(Vector3 vector3)
    {
        patrolPositions.Add(vector3);
        editorPatrolPoint = patrolPositions.Count - 1;
    }

    public void NextPatrolPoint()
    {
        editorPatrolPoint++;
        if (editorPatrolPoint >= patrolPositions.Count)
        {
            editorPatrolPoint = 0;
        }
        this.transform.position = patrolPositions[editorPatrolPoint];
    }

    public void RemoveCurrentPatrolPoint()
    {
        if (patrolPositions.Count == 0) return;
        patrolPositions.RemoveAt(editorPatrolPoint);
        if (editorPatrolPoint >= patrolPositions.Count)
        {
            editorPatrolPoint = patrolPositions.Count - 1;
        }

        if (patrolPositions.Count > 0)
        {
            this.transform.position = patrolPositions[editorPatrolPoint];
        }

    }
}
